Welcome back in this lecture.
We're finally getting into the meat and potatoes of our game, which is scripting the system responsible
for handling waves.
This script will start the game once a player spawns into the map and begins a countdown for the first
wave to begin.
Then the script will spawn the zombies for the first wave on the map for the players to kill.
Once all the zombies are dead, it will move into an intermission state before starting the next round,
and it will continue this loop until all the players beat all of the waves or all the players die in
our game.
Either way, we'll have the script, clean up the game, and then wait for a new player to spawn in
to start this loop all over again.
So my plan is to have a total of 11 waves, with the final wave featuring the strongest zombie boss.
So let's go back to our game handler script, which is going to be responsible for this wave system.
I want to define a table and I'm going to call this table my zombie count per wave.
And this is going to tell me how many zombies I should spawn and what type for each wave in my game.
For example, for the first wave in my game, I want to have a set of regular zombies, and I'm going
to set the amount of regular zombies to a value of like 12.
So that means at each one of our spawns, there will be a total of three zombies coming out of them.
That's for the first wave.
And then we can continue on and set how many zombies we would like for the next sequential waves.
For example, for the second wave, maybe we can bump up this value to 20.
For the third wave, we can continue to add more zombies, but this time I'm going to decrease the amount
of regular zombies, and instead we're going to introduce a new zombie, which is our fast zombie.
So let's go ahead and make sure that the keys that we're placing inside of this table match the names
of our zombies in server storage.
So if we want to add some fast zombies, let's go ahead and create a key for a fast zombie.
And that's going to be a total of.
We could do something like eight fast zombies, and that's going to be for wave number three.
And then again we can copy this and do something for wave four.
We'll bump up this value to something like 24.
And then we'll add an additional fast zombies.
And then for the fifth wave again, we can set this to 24.
We'll bump up this value to 12, and then we can introduce another new enemy like our tough zombie and
set that value to something like four.
And then we can copy this and move on to the next wave, which is wave six.
Here we'll bump up the amount of enemies even more.
We'll have this be at 28.
The amount of fast zombies will have will be 16.
We'll increase this to eight.
And then for wave number seven.
We'll keep this value at 28.
We'll keep this one at 16.
We're going to increase the amount of tough zombies to ten.
And then we can introduce another new enemy, which is going to be our fast zombie boss.
And then we can spawn two of those guys onto our map.
Again, we'll copy this and do it for our eighth wave.
For the eighth wave, we could do something like bump this up to 34 for the fast zombies.
We'll bump this up to 20 for the tough zombies.
We can bump this up to 12, and then we'll double the amount of fast zombie bosses.
And then again, we can introduce another new enemy.
And this can be our tough zombie.
Let me make sure I spell this correctly.
Tough zombie boss.
And we'll place two of those guys onto the map and actually move this down so our table doesn't get
too long.
And then we can copy this and move on to the ninth wave.
And for the ninth wave, we can bump up this to 36.
We'll set the amount of fast zombies to 28, something like that.
We'll bump this up to 16.
We can bump this up to, let's say, five of these guys.
We'll bump this up to four of these guys, and then we'll introduce another new enemy.
And that's going to be our lightning zombie.
And we can spawn something like, let's say, eight of those guys onto the map.
And then again, we can copy this and do it again for our 10th wave.
We could bump this value up to 40.
We could keep this value the same.
We'll bump up the amount of zombies equal to, let's say, 18.
We'll bump up the amount of fast zombie bosses to, let's say eight.
And then the tough zombie bosses will bump up to five, and then the lightning zombies will bump up
to 12.
And then we'll copy this once more.
And for our final wave, which is wave 11.
We'll bump up this to 44.
We'll bump this up to 30.
We'll bump this one up to 20.
We'll keep this one the same, but we'll add an additional tough zombie boss.
We'll bump up this value to, let's say 14.
And then we're going to add our final zombie, which is our ultimate zombie boss.
And we're going to add one of those guys into our map.
Now you can totally have the freedom to change these values however you'd like to balance out the game
in whatever way you see fit, but I'm just going to keep it at these values for now.
Next thing I want to go ahead and do is I want to keep track of the total waves that we're going to
have in our game.
So let's go ahead and make a few constants one to signify the total amount of waves in our game, which
is 11.
We also want to define how long we should wait in the intermission stage between waves.
So we'll call this our wait time for the intermission.
And we could do something like 60s.
And then we can also define the wait time when we are in the starting intermission.
So we'll call this wait time intermission or underscore start underscore intermission and we'll do something
like 30s.
Then we can go ahead and define a bunch of functions for what we want to do in each one of the different
states that our game can be in.
For example, what do we want to do when we're in the starting intermission?
So we can call this function on start intermission?
What do we want to do when we're in the regular intermission?
We'll call this function on intermission.
What do we want to do when we are in the waves in progress state.
So we'll call this function on start wave.
What do we want to do when the game is over and all the players lost?
We'll call this function on game Over.
And then we could copy this and do the exact same thing, except for when the players have won.
So we could call this on game over win.
And then what do we want to do when we're cleaning up the game and we're in that waiting intermission
state?
So we call this function on waiting.
So when we go down here and we set the workspace as game state to the start and intermission, this
is basically going to set our loop into action.
So that means we need to listen for when the workspace has the game state attribute changed.
And then when the attribute changes we want to check what exactly the current game state is, and then
call the associated function based on that game state.
So what we can go ahead and do is we can listen for when the workspace get attribute change signal.
And we're going to be listening to the game state we want to listen for when that is changed.
And then we can go ahead and basically place all of these functions inside of a table and then associate
these functions with a particular key.
So this is going to act as a switch statement.
If you've ever heard of those in other programming languages, which basically allows you to execute
a block of code based on an input.
Unfortunately Lua doesn't have switch statements, but we can use tables to imitate a switch statement
by using a dictionary.
So I'm going to create a table called Intermission functions.
And we're going to associate each one of these states that our game can be in with one of these functions
up here.
So for example, one of the keys could be for our game state enum of start intermission.
What function will be associated with that.
Well that would be associated with our on start intermission function.
And we don't want to call it here.
Instead we want to associate this function with this key.
That way when the game state changes, we can check what the current game state is, grab the associated
function with that game state and then execute that function.
The next would be our game state enum of intermission.
We'll associate that one with the en intermission function.
And then we'll copy this and then do the same thing, but this time for the wave in progress and associate
that with the on start wave function.
Again.
We could do this for the game over game state, and we'll associate that with the on game over function.
Copy this and then listen to the game over win and associate that with the on game over win function.
And then the last state is going to be our waiting state.
And we'll associate that with the on waiting function.
So now what we can go ahead and do is we can get the current game state which is equal to workspace
get attribute game state.
And then we could compare this value with the values inside of our intermission functions table and
get that particular callback function and execute it.
So we'll make a variable.
We'll call it callback.
And that's going to be equal to our intermission functions.
And then we're going to pass the current game state.
And if we have a callback inside of this table.
So if we got a value stored inside of this variable, then we can go ahead and call that function.
So just as a placeholder, what I'm going to do here is I'm going to print.
Starting intermission.
I'll print here.
Intermission.
And in here I'll print wave in progress.
I'll print in this one.
And game over.
Lose.
Here.
I'll print Game Over win.
And then here I will print cleanup.
And the purpose of each of these functions is after they're done executing their specific functionality,
they're going to set the attribute on the workspace of game state to the next, um, game state.
For example, if we're in the wave in progress and then the wave is over, it's going to set it back
to the intermission, and then the intermission is going to wait and then set it back to the wave in
progress.
And it's going to continue that loop until we either lose or we win.
So to demonstrate this loop, what I'm going to do is in the on start intermission function, I'm just
going to wait for five seconds.
And then on the workspace, I'm going to set the attribute of game state equal to the wave in progress
game state.
So we're going to do game state enum dot wave in progress which is going to trigger this function.
So this is going to print out wave in progress.
And then we're going to yield for five seconds.
And then we're going to set the workspaces game state to the intermission which is going to execute
this function.
And then we'll yield in here for five seconds.
And then we'll set the attribute to the.
Game state enum of wave in progress, and then that will continue that loop.
And just to keep track of it, I'll create a temporary variable out here, call it I.
And each time through this loop we're going to increment I by one.
So we'll do I plus equal one.
And then if I goes beyond let's say three.
Then what we can go ahead and do.
Is will set the.
Attribute to the game over win, so the game is over.
Otherwise, we'll set the attribute to another wave that is in progress.
And that should trigger this function right here, which is going to basically display to all the players.
Hey, you won.
And then it'll trigger the cleanup.
So we'll wait here for five seconds.
And then we'll set the attribute on the workspace to the waiting attribute.
And that's going to trigger this function.
And inside of here, we'll wait for five seconds and then set the attribute back to the starting intermission,
which is going to force the loop to start all over again.
And then I'm also going to make sure to set I back to one when we set this to the game over win attribute.
Okay, so this should demonstrate the entire loop of our wave system.
So if we go and just run our game, we should see printed in the console that we are in the starting
intermission.
And then we should see that we are in a wave in progress.
And then when that wave is over, we should get placed in the intermission when the intermission is
over.
We should get placed back into a wave in progress.
So it's going to do that for three waves in total.
So we're back in an intermission.
And then we're back in a wave and this is our third wave.
And then we should go to the game over when we're back into an intermission.
So maybe it'll do four waves.
Game over, when actually, that's kind of weird.
So we're in a game over win and then we're in the cleanup.
And now we're back in the starting intermission, and it's going to do that entire loop all over again.
So this is our game loop.
I'm actually kind of interested to see why it set it to the intermission.
So.
We go back.
When we increment I.
If I is greater than three.
Oh we could we should have done, uh, greater than or equal to three.
But you get what I mean.
It'll go for three waves.
And then once the three waves are over our players, one, it triggers the cleanup.
And then the cleanup puts us back in the start intermission.
And then it starts the next wave, and it just continues that loop forever and ever and ever.
So this is the kind of system we want to implement for spawning zombies into our game.
So for example, when we get set to the start intermission, what we want to do is have a countdown
here of 30s to let all the players know that, hey, we're going to be starting, uh, the first wave
and a certain amount of seconds.
So this means our if I go and enable UI visibility, this guy up here is going to have to come into
play for our clients.
That is our game state guy.
It's simply a text label.
And we're going to update the text in this text label to communicate to the player, like what wave
we are in, how many zombies are left alive if we're in the cleanup stage, stuff like that.
So we have an event inside of replicated storage to communicate between the client and the server,
to update that text label for that player.
So we can go ahead and make a reference to that event.
I'm going to call it my game event.
And that's in replicated storage dot remotes.
And it's called Game event.
And then we want to be able to create a standard of communication between the client and the server
with this event.
So let's go ahead and create a new module script inside of replicated storage.
I'll just duplicate this game state enum that we already have.
And inside of here we'll have a section for actions to be given to the client.
So we'll call this two client.
And one of the actions we want to give to the client is for them to update the text on their screen.
So we'll call it update text and set equal to itself.
And then we'll rename this to our game Comms enum.
Now we can go ahead and use this enum.
So we'll require it Game.com enum.
And we'll require for replicated storage dot modules dot enums dot game comms enum.
And then now that we have this event and this enum inside of our starting intermission, what we want
to go ahead and do is when we're starting the intermission, we'll use the game event and fire to all
of the clients in our game.
Hey, you need to update that text on your screen, so we'll tell them to update the text and the text
will update it to is.
We want to tell them that we're waiting for players to join the game, because we're in the starting
intermission.
And then what we're going to do is since there's not going to be any players spawned onto the map,
we need to wait for when a player is added to our live team, and that will notify us when a player
has pressed the play button and spawned into the map, which means we can start the countdown for the
start intermission.
So inside of the team service, we're going to wait for the player added event to be fired for our live
team.
Once that gets fired, that means a player has spawned into the map and we can go ahead and start our
countdown.
So we're going to create a while loop.
The starting index for I is going to be equal to our wait time for the start intermission.
And then we're going to go all the way until we hit one second.
And we're going to subtract by one each time.
And what we're going to do here is we're going to copy this event, but this time we're going to set
the text to be waves our starting in.
And then we can go ahead and concatenate this with the current index that we're at.
And we'll say seconds.
And then we'll make sure to yield for one second each time through this for loop.
Now, something very important to note is I want the game over, lose game state to execute when there
are no longer any players left on the alive team.
Now that means if a player joins the game and they get put on the alive team, but then they decided
to troll and then reset right away, well, that means it's going to trigger this state, and that means
we don't want to continue through this loop for our countdown.
So another thing we should check inside of this countdown is if the game state is still equal to the
start intermission.
If the workspace getattribute game state if it is not equal to the game state enum of start intermission,
then that means we know that a player or all the players in our map have died, so we should go ahead
and just return out of this function and do nothing else.
Otherwise, once we reach the end of this for loop, we can go ahead and set the game state to the game
state of wave and progress.
And just as an extra set or layer of security, we're also going to put this if statement on the outside
of our for loop, just to make sure we're still in the start intermission.
And if we're still in the start intermission, then it's okay for us to set the game state to waves
in progress.
Now, in order for the clients to see this text appear on their screen, we need to go ahead and create
a new local script to listen for this game event.
So let's create a new local script inside of our game state guy and we'll call this our game state Guy
handler.
And inside of here, what we need to do is get replicated storage to refer to our game event as well
as our game comms enum.
So we'll go ahead and grab replicated storage.
And then we can go ahead and get our game comms enum.
And will require from replicated storage modules, enums, game comms, enum and then will make a reference
to our game event.
So that's then remotes dot game event.
And then we also make a reference to our GUI which is script dot parent.
And then we'll get the text label that is inside of our GUI.
So that's in GUI dot frame.
And then we'll get the text label.
And now what we can go ahead and do is we can listen for when the game event is fired.
So we'll listen to on client event.
And then we'll connect a function.
And the server is going to give us an action as well as some text to update on our screen.
So if this action is equal to our game comms enum of two client dot update text, then we can go ahead
and set the text label's text property equal to this text from the server.
And that's all we need to do for our game state UI handler.
Now we can go ahead and test what we've gotten written down so far, and we should see a countdown appear
on our screen when we are set to the start intermission.
So if we go and play test the game.
And we go and play the game.
As you can see it now, says waves are starting in however many seconds, and as one second goes by,
it continues to decrement this value and then eventually it should go to 1 or 0, and then it should
start the first wave.
So we'll go ahead and pay attention inside of our console if it prints that message of wave in progress.
So 54321.
And then there we go.
Wave in progress.
And this is where we should update the text on the player's screen again and tell them that, hey,
a wave is in progress, stuff like that.
And you can also see that our shop is opening and closing.
See, we're in the intermission state.
So the shop opened, but then when we are in Game Over or we were in a wave, then the shop closes down
and we can't interact with the shop anymore.
But then once we're back in the starting intermission, as you can see, we can now interact with the
shot, which is very cool.
Now, what do we want to do when the game state is set to waves in progress?
Well, it's going to trigger our on start wave function.
And what this should do is tell all the players that a wave is starting, and then we should basically
display on the screen that a wave is in progress, how many zombies are left.
And then we should spawn all of these zombies onto the map for our players to fight.
So what we're going to do is we're going to get rid of this yield statement here.
And we want to keep track of what wave we're currently on.
So we're going to replace this eye variable here.
We're just going to get rid of all of this for now.
And we'll create a new variable up here that's going to keep track of the current wave.
And we'll just call it current wave.
And we're going to set that equal to one by default or actually no, we'll set it to zero by default.
And then we'll go down.
And when we start a wave, we'll set current wave plus equal one.
And then we want to get a table of all these zombies we need to spawn on the map.
So we'll call this zombies to spawn.
And what we should do is we should loop through all of the zombies that are currently in whatever table
for what wave we're in.
So if we're in wave number one, we're going to loop through all of the key value pairs and grab the
total amount of zombies we need to spawn.
So what we can do?
Is will loop through every single zombie and the amount in the zombie count per wave.
And we're going to index it with the string of wave.
And then we're going to concatenate that string with whatever current wave we're at.
And what we're going to do is we're going to make a clone of this particular zombie and insert it into
our zombies to spawn table.
So for I equal to one with the amount of zombies, what we need to do is make a clone of this zombie.
So we'll basically need to get a reference to our zombies folder which is in server storage.
So let's grab server storage.
And then we'll have a variable to refer to our zombies folder, and we'll set that equal to server storage
dot zombies.
So now we have a reference to the folder where all the zombies in our game are stored.
And then we can go ahead and refer to our zombies folder and then index it with the particular name
of our zombie, which is right here.
So we'll pass that right there.
And then we're going to make a clone of that zombie.
And then we can go ahead and insert this clone into our zombies to spawn table.
And then once we have all of the zombies we need to spawn inside of our table, we can go ahead and
tell all of the players in our game, hey, a wave is in progress and this is how many zombies are left
to fight.
So we'll fire to all of the clients that wave, and then we'll index this with whatever the current
wave is at.
So wave number one, wave number two, whatever wave whatever is in progress.
And then we'll separate this and say something like how many zombies are left?
So we'll concatenate this with a value to represent how many zombies are left in the game.
So let's make a variable for that.
We'll call this zombies left.
And that's going to be equal to the number of zombies to spawn in our table.
So the number of zombies left.
And then we'll concatenate this with the string of zombies left.
So if it's wave one and we have to fight 12 zombies, it'll say wave one in progress.
12 zombies left.
Now, what we need to go ahead and do is have a loop executing here that's going to loop through and
randomly spawn all the zombies on the map in a circular motion.
So basically we're going to start at one spawn and then move to the next spawn, and then move to the
next spawn and move to the next.
And continue in that loop until there are no more zombies left to spawn.
So a perfect way we could do that is by using a repeat loop.
We're going to repeatedly spawn zombies on the map until we have no more left to spawn.
So what we can go ahead and do is pick a random zombie out of our zombies to spawn table by generating
a random number, we'll call this random num, and that's equal to RNG.
Next integer.
And we actually need to create a random data type.
So let's do that as well.
RNG is equal to random dot new.
So we'll generate a new integer from one to the length of our zombies to spawn table.
And then we can go ahead and get that zombie at this index.
And we want to go ahead and position this zombie at one of the spawns in our map.
For example, if we need to position the zombie over here, we'll set it to this spawn and set the humanoid
root part of that zombie equal to the position of this attachment in our world.
So we need to also create a variable to store all the different zombie spawns that we have in our map.
So up here we'll create another variable.
And I'm going to call this zombie spawns.
And that's going to be equal to workspace dot spawns dot zombie spawns.
And we're just going to get all of those spawns and store it in a table.
And then we can go ahead and refer to this zombie.
We'll get their humanoid root part and set the key frame equal to one of the positions of the attachments
that are in our spawn.
Now, since we only have four spawns and we want to go in a loop starting at one and then going to the
next one, next one, and then going back to one and the next and the next, we need to keep track of
what current index we are inside of the array that is storing all of our zombie spawns.
So let's create a variable outside of our repeat loop.
We'll call it spawn index and set it equal to one.
And then we can refer to our zombie spawns.
Get the spawn at this current spawn index, and then we'll refer to the attachment that is inside of
that part, and then get its world keyframe.
And then we can go ahead and increment our spawn index by one.
So we'll do plus equal one.
And then we'll make sure to check if this spawn index goes beyond the number of spawns that we actually
have in our map.
So if spawn index is greater than the number of zombie spawns we have, then we can just go ahead and
set spawn index back to one.
And this allows us to loop through each one of our zombie spawns.
Once we've successfully positioned our zombie to the correct area on our map, then we can go ahead
and refer to this same zombie and set its parent equal to the folder in our workspace.
So let's create a variable for that as well.
I'll call this zombies workspace and that's equal to workspace dot zombies.
And then we can go ahead and set the parent of this zombie equal to our zombies folder in the workspace.
Now that our zombie is in the workspace, we need to go ahead and listen for when this zombie dies.
Because when this zombie dies, we need to update the text displayed for the players to tell them how
many zombies are left.
So if this particular zombie to spawn at this index, we're going to get their humanoid and we're going
to listen to their died event.
And with this, what we can go ahead and do is we can decrement the zombies left the variable.
So we'll do zombies left minus equal one.
And then we can just basically copy what we've done right here and give this new updated text to our
players.
And now, every single time a zombie is going to die, it's going to decrement it and tell the players
eventually, once there are no zombie left.
And we need to check inside of this event when there are no zombies left.
So if the number of zombies left is equal to zero.
Then what we need to do is we need to set the game state to the intermission game state.
So as long as the zombies that are left are zero.
And we're still in the wave in progress game state.
So if the workspace get attribute game state is equal to the game state enum of wave in progress.
Then we can go ahead and set the workspace to the intermission.
State, but we only want to do this if the current wave that we're at is not the last wave.
So if the current wave that we're at is not equal to the last wave, which would be the 11th wave,
then we can go ahead and set it to the intermission state.
Otherwise, this means that our players have beat the game.
So players beat the game because they are at the last wave and all of the zombies have died.
Then this is where we would set the game state to the game state.
Enum of game over.
Win.
And like I said, we want to continually spawn these zombies on the map until the number of zombies
we have left to spawn in this table is zero.
So if the number of elements in our zombies to spawn table is equal to zero or less than or equal to
zero, we'll just do that.
Or we also want to stop spawning zombies in the workspace when, for example, all of the players die
in our game.
So let's say we're repeatedly spawning zombies on the map.
But while we are spawning zombies on the map, all of the players have died.
Then we want to also stop spawning zombies.
So we'll do workspace get attribute game state.
If the game state is no longer equal to the game state enum of wave in progress, then we don't want
to spawn any more zombies.
And then, in order to keep track of how many zombies are left in our zombies to spawn table after we
have spawned the zombie onto the map and we're listening to their diet event, we can go ahead and remove
them from our zombies to spawn table.
So table dot remove zombies to spawn at this current random number index.
And then a very important thing we need to do is add a yield statement in here.
Because I don't want all of my zombies to spawn instantaneously.
So we'll put a yield statement in here of let's say 0.25 seconds.
Okay, so now this means once the start intermission is over and we get put into the wave in progress
state, this function is going to execute, and then it's going to go through and spawn all of these
zombies for a particular wave onto the map.
And it's going to listen for when all of those zombies are dead.
And when all the zombies are dead, if we're at the last wave, we're going to set the game to be over
and the players have won.
Otherwise we're going to set it back to the intermission.
So let's go ahead and test what we've gotten written down so far.
Currently we are in the starting intermission and if I play.
We now have to wait through this set of 30s.
So I'll go ahead and wait for that to be over.
321.
It should tell me how many zombies.
There we go.
Wave one in progress.
12 zombies left.
And as you can see, the zombies have been placed in their particular spawn areas.
So if I go walk over here, they should start chasing after me.
As you can see, there's three zombies in that spawn.
And then if I run down here, there should be another set of three zombies over here.
Okay.
There's one.
Only one zombie.
There should be more in here.
So far, we're being chased by six zombies.
Oh, I guess they did.
I wonder where they came from.
And then here's another six zombies.
And then where is my final six or my final three?
My final three zombies are over here as well.
Okay, perfect.
They all spawned in their areas and now I'm being chased by 12 zombies.
So now what we need to do is we first need to give our player a weapon to defend themselves on this
first wave, because clearly they're not going to have any money to buy any weapons.
So we need to give all the players, like the starting knife to defend themselves against the zombies.
And when our zombies die from these guys.
So let me go ahead and die.
When all the players in our game die, we need to go ahead and display the message that all of our players
have lost, and we need to go ahead and clean up all these zombies off of our map.
So to tackle this issue back inside of our game handler.
When the respawn event is fired for a particular player, and then we place them on the map, we need
to go ahead and give them a knife or a starting knife to defend themselves with.
So inside of server storage, we're going to get the knife tool and we're going to make a clone of that.
So we'll get that clone.
And we want to go ahead and give that to the player.
So we'll set the parent equal to that player's backpack.
So now all the players that spawn into our game will have this knife to defend themselves.
And then we need to listen for when there is no players left in our live team.
So inside of our teams and we get the live team, we want to listen to the player removed event and
connect a function.
And here we want to check if the number of alive players is equal to zero.
So we'll get the number of alive players, or we'll get all the alive players.
That's going to be equal to teams.
Dot alive get players.
And if the number of alive players is equal to zero.
Then that means we should set the workspace attribute of game state equal to the game state enum of
game over.
But of course we only want to do this if the workspace is game state is not equal to the game over game
state or the waiting game state.
So for example, if the workspace get attribute game state.
If that is equal to the game state of let's say we're already in the game over game state, then I want
to ignore this code down here.
So this is where we would just return.
Another thing I want to ignore is if we're in the game over win game state.
So let me copy this paste this here.
If we're in the game over win then I also want to ignore this code down here.
Or let's say we are in the waiting game state.
Then I also want to ignore this code down here.
So if we're in the game state of waiting, then we're also going to ignore this code.
So we're only going to set the attribute on the workspace to the game over game state.
If we're in the intermission or the wave in progress game state.
So now this means if I go and playtest my game.
And I jump in to play.
As you can see, I got my knife from the server to defend myself.
And now we're just going to wait for this countdown to complete.
And we're going to have all these zombies come after us.
And then here I have all these zombies coming after me.
If I go ahead and start killing these guys, let me just clean these guys off the map.
Okay.
Got that set killed off.
Let's go ahead and go to the zombies over here.
There should be three zombies over here.
So there's my first, second and third.
Let's go ahead and kill these guys.
Are.
Those guys are dead?
Let's run over here.
Let's go ahead and kill these guys.
That guy's dead.
Dead?
And they're dead.
And as you can see, it's updating the text on our screen when those zombies die.
So now it's telling us we have three zombies left.
Very cool.
Let's go ahead and kill these last guys.
And after all, these guys are dead, it should set us back to the intermission state.
So let's go ahead and see if it does that.
So all these zombies are dead.
And as you can see, it printed in the console.
Intermission.
So right now we're in the intermission.
And it should set us back to the next wave.
Or actually, I believe.
Yeah.
So we haven't done anything in our intermission function.
So we actually need to go ahead and fill this out.
So it did set us to the intermission state.
So now we need to script what exactly we would like to happen when we are in the intermission state.
Well, what we want to go ahead and do is basically the same thing that we've done up here.
So we'll just copy this code and paste it in here.
And we want to wait for the total amount of time for the regular intermission, which is 60s.
And then we'll change this value here to be for the regular intermission as well as right here.
And then we're just going to display that we are currently in an intermission.
And that we have however many seconds until next wave.
So once we kill all of these zombies and we get placed into the intermission state, it's going to do
a countdown of 60s.
And then once that countdown is up, it's going to allow us to move to the next wave.
Okay, so I got three zombies left.
After I kill these three guys, it should set us to the intermission state.
And then we should see a countdown appear on our screen.
So let's go ahead and kill these guys.
Yeah, perfect.
It says intermission, however many seconds until the next wave.
So when this intermission is up, it should start the next wave and spawn the next set of zombies.
So let's go ahead and wait for this intermission to end, and we'll see if it starts the next wave.
We got five, four, three, two, one.
Perfect.
We now are in wave two.
So wave two in progress.
And now we have 20 zombies left.
We need to fight.
And you can also see that I have gotten some money from killing these zombies.
So every time I kill my zombie, I get some money.
Another thing we could implement later in a future lecture is allowing us to earn some extra money when
a wave ends.
So at the end of each wave, we could have a reward for our players to have some extra bit of money.
But for now, let's just say the zombies kill me and I die.
It should set the game state to the game over and we lost.
So let's go ahead and see.
There we go.
We have died.
And as you can see in the console it printed game over lose.
So we've lost.
So in that state we could have a message print out saying like all the players lost.
And then it should set us to the clean up state or the waiting state.
Too many print statements coming from my zombies, so it's kind of flooding my console.
Actually, a neat little tip I want to show you guys is if we don't want to have the zombies print this
garbage out in our console anymore, and you want to be able to quickly remove it without having to
go into each one of the individual scripts for your zombie.
I well, you can go ahead and do is you can press control, shift and F on your keyboard to open up
this little menu here.
And it's also in the view tab.
It's called find All, replace All, and we can go ahead and search for our print statement when we're
printing wandering into the console.
So if I search for that boom, it shows me all the results from all of these scripts where this exists.
And then I can replace this with a value.
So if you push down this little drop down arrow, you can give a value you would like to replace it
with.
And in this case I just want to delete all of them from my zombie AI scripts.
So we can just hit replace all hit.
Yes.
And now it has deleted that print statement from our zombies for us, which is very cool.
This is just a little extra neat feature in Roblox studio to allow you to replace or find things in
scripts very quickly.
However, now what we want to do is when the game state is set to the game over, we lost.
Then we should print a message or give a message to all of our players saying, hey, you guys lost
and then we'll wait for a few seconds and then set the game to this waiting state, and this function
will clean up the game for us.
So for example, here, what we need to do is I'm going to copy this up here.
And then place it here.
But instead, the message we're going to give to our players is that we lost.
So we'll say game over.
And we'll say zombies win.
And then we'll wait for a random amount of time like 10s.
And then we're going to set the game state on the workspace to be equal to the game state enum of waiting.
And then this function will go ahead and clean up the game for us.
So what we want to do in this particular instance is we want to tell all the players that we are cleaning
up the game.
And then we want to delete all of the zombies that are currently on the map.
So we'll refer to our zombies workspace folder, and we're going to clear all of the children inside
of there, which will delete all of those zombies.
And then another thing I want to do actually is in the workspace filtering folder for the bullet holes,
just in case any players were shooting up the map and there were bullet holes all over the place, I
can go ahead and clear all of those real quick as well.
And then we want to reset the current wave back to zero.
And then another thing we want to do is when we are cleaning up everything, and then we want to start
a new set of waves.
We want to reset the money for all of our players back to zero.
So for every single player in our game and players jet players, we're going to refer to their leader
stats.
And we're going to set their money value equal to zero.
And then we also want to go ahead and kill any players that are still on the map.
So if we won the game, for example, because this state is going to be, um, enabled when we either
lost the game or we've won the game.
So just in case there are still players on the alive team, we're going to loop through every single
alive player in Teams Alive get players.
And we're going to refer to this live player, get their character, get their humanoid, and change
the state of this humanoid to the enum humanoid state type of dead.
So that will kill all of the players in our game.
And then we're going to put a yield statement here of like five seconds.
That way this cleaning up game message stays on the screen for about five seconds.
And then after that, we can have another countdown here to say that we're going to be starting a new
game in however many seconds, so we can have a small countdown of like 10s.
So we'll put our for loop here.
And we're just going to copy this, paste this here and say that we're going to be starting a new game.
N and then we'll concatenate this with our current index.
And then we'll say we're starting a new game and however many seconds.
And then we'll make sure to yield for one second each time.
And then we can go ahead and set the attribute on the workspace to the start intermission.
So now let's go ahead and test to see if this is working.
So we'll play our game.
And I'm waiting for all my zombies to spawn in and let's have my zombies kill me.
So if I walk over here.
Let's have these guys smack me to death.
And then when I die, it should hopefully clean up the game for us.
So these guys are hurting me.
They're hurting me.
Always.
I'm getting hurt real bad, and eventually they should kill me.
Okay, there we go.
I'm dead.
There we go.
It says game over.
Zombies win.
And then it deleted all the zombies off the map as well.
Hopefully.
No, they're still there.
Okay, there we go.
Now they're all cleaned up.
It says cleaning up game deleted all of these zombies, and now it says starting a new game in however
many seconds.
And if I try to press the play button, I can't spawn into the map because we're not in the starting
intermission.
But as you can see, it has set the game back to the starting intermission and it says waiting for players.
And if I play the game, boom!
Now we're back in the starting intermission and it's starting the countdown again, and we're going
to go back to the first wave.
So that's working great.
Now let's say I were to reset my character in the middle of this countdown.
So if I die, game over.
Zombies win because I was the only player on the alive team, and now we have to wait for the game to
clean up the map again.
Perfect.
The last thing that we can go ahead and fill out is when we win the game.
So we'll just copy this and we'll just paste this in here and say that the game is over, but you win
just like that.
And then we'll wait for 10s and then put the game in the cleanup state.
Okay.
And the next lecture, we're going to continue improving upon our wave system by adding sound effects,
giving money to players at the end of a wave.
We're also going to highlight the last zombie on the map, so that way it's easier for the players to
see where exactly the last zombie is and stuff like that.
So I will see you in the next lecture.